import scipy

class PatchGroup():
    """
    A class to thelp with keeping multiple PatchStims together logically
    Methods:
        can_rotate(self, bool)                  sets the self.rotatable variable to bool value
        move(self, direction='up', amount=10)   moves all objects in direction specified by amount given
                                                    movement is relative to orientation though so up is
                                                    towards top of object not top of screen.
        add_patch(self, patch)                  adds patch to the group
        rotate(self, direction='cc', amount=10) rotates object group in direction cc=counterclockwise
                                                and c=clockwise amount is in degrees
        scale(self, amount)                     scales object group by factor given (1.0 being no scaling).
        draw(self)                              draws all patches in order they were added.
    """
    def __init__(self):
        self.ori       = 0.0
        self.pos       = scipy.array([0,0], dtype=scipy.float64)
        self.size      = 1.0
        self.patches   = []
        self.offsets   = []
        self.oris      = []
        self.rotatable = True
        self.scalable  = True

    def can_rotate(self, rotatable):
        self.rotatable = rotatable

    def can_scale(self, scalable):
        self.scalable = scalable

    def draw(self):
        for patch in self.patches:
            patch.draw()

    def move_to( self, pos ):
        self.pos = pos
        # update the positions of all the patches
        for i in xrange(len(self.patches)):
            self.patches[i].pos[0] = self.pos[0] + self.offsets[i][0]
            self.patches[i].pos[1] = self.pos[1] + self.offsets[i][1]

    def rotate_to( self, ori ):
        rotation = ori - self.ori
        self.rotate(amount=rotation)

    def move(self, direction='up', amount=10):
        ang = self.ori * scipy.pi/180.0
        rot_matrix = scipy.array([[scipy.cos(ang),scipy.cos(ang+scipy.pi/2.0)],\
                                  [scipy.cos(scipy.pi/2.0-ang),scipy.cos(ang)]])
        if direction == 'up':
            d = scipy.dot([0,amount],rot_matrix)
        if direction == 'down':
            d = scipy.dot([0,-amount],rot_matrix)
        if direction == 'left':
            d = scipy.dot([-amount,0],rot_matrix)
        if direction == 'right':
            d = scipy.dot([amount,0],rot_matrix)
        self.pos += d
        # update the positions of all the patches
        for i in xrange(len(self.patches)):
            self.patches[i].pos[0] = self.pos[0] + self.offsets[i][0]
            self.patches[i].pos[1] = self.pos[1] + self.offsets[i][1]

    def add_patch(self, patch):
        self.patches.append( patch )
        self.offsets.append( patch.pos - self.pos )
        self.oris.append( patch.ori - self.ori )

    def rotate(self, direction='cc', amount = 10):
        # construct the rotation matrix
        if direction == 'c': # seems backwards, because of psychopy standard
            amount = amount
        if direction == 'cc':
            amount = -amount
        
        ang = amount * scipy.pi/180.0
        rot_matrix = self.rot_matrix = scipy.array([[scipy.cos(ang),scipy.cos(ang+scipy.pi/2.0)],\
                                  [scipy.cos(scipy.pi/2.0-ang),scipy.cos(ang)]])
        # rotate all the offsets first
        self.offsets = [scipy.dot(offset,rot_matrix) for offset in self.offsets ] 
        # update the positions of all the patches
        for i in xrange(len(self.patches)):
            self.patches[i].pos[0] = self.pos[0] + self.offsets[i][0]
            self.patches[i].pos[1] = self.pos[1] + self.offsets[i][1]
        
        # update the orientation of the group
        self.ori += amount
        for i in xrange(len(self.patches)):
            self.patches[i].ori = self.ori + self.oris[i]

    def scale(self, amount):
        self.size *= amount
        # scale up everything indvidually
        for i in xrange(len(self.patches)):
            self.patches[i].size *= amount
            self.patches[i].setSize( self.patches[i].size.copy() )
        # scale up offsets
        self.offsets = [offset*amount for offset in self.offsets]
        # reposition everything
        for i in xrange(len(self.patches)):
            self.patches[i].pos[0] = self.pos[0] + self.offsets[i][0]
            self.patches[i].pos[1] = self.pos[1] + self.offsets[i][1]
        

